package com.db.concurrency.factorizer.cached.computable;

import java.util.concurrent.*;

/**
 * @author Alexander Kotov (kotov.alex.22@gmail.com)
 */
public class CachedComputable3<A, V> implements Computable<A, V> {
    private final ConcurrentMap<A, Future<V>> cache = new ConcurrentHashMap<A, Future<V>>();
    private final Computable<A, V> c;

    public CachedComputable3(Computable<A, V> c) {
        this.c = c;
    }

    @Override
    public V compute(final A arg) throws InterruptedException {
        Future<V> result = cache.get(arg);
        if (result == null) {
            Callable<V> task = new Callable<V>() {
                @Override
                public V call() throws Exception {
                    return c.compute(arg);
                }
            };
            FutureTask<V> ft = new FutureTask<V>(task);
            cache.putIfAbsent(arg, result);
            if (result == null) {
                ft.run();
                result = ft;
            }
        }
        try {
            return result.get();
        } catch (ExecutionException e) {
            throw new RuntimeException(e);
        }
    }
}
